﻿using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
using Unity.Collections;

internal class CustomPassSSPR2 : CustomPass
{
    // It can be used to configure render targets and their clear state. Also to create temporary render target textures.
    // When empty this render pass will render to the active camera render target.
    // You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
    // The render pipeline will ensure target setup and clearing happens in an performance manner.

    public bool ShouldRenderSSPR = false;

    [Tooltip("绘制反射平面所用材质球")]
    public Material ReflectionPlaneMaterial;

    [Tooltip("绘制所用反射平面网格")]
    public Mesh ReflectionPlaneMesh;

    [Tooltip("反射平面中心位置")]
    public Transform ReflectionTransform;

    [Tooltip("获得反射内容缓存的ComputerShader")]
    public ComputeShader SsprComputerShader;

    [Tooltip("反射缓存贴图高度")]
    [Range(256, 1080)]
    public int RTHeight = 0;//真实的rt垂直大小

    private int RTWidth => Mathf.RoundToInt(RTHeight * (float)Screen.width / Screen.height);//真实的rt水平大小

    public float ReflectPlaneHeight => ReflectionTransform.position.y;

    [Tooltip("反射在屏幕淡出宽度")]
    [Range(0.01f, 1f)]
    public float FadeOutScreenBorderWidthVerticle = 0.25f;

    [Tooltip("反射在屏幕淡出高度")]
    [Range(0.01f, 1f)]
    public float FadeOutScreenBorderWidthHorizontal = 0.35f;

    [Tooltip("反射内容色调调整")]
    public Color FinalTintColor = Color.white;

    private static int ReflectColorRT = Shader.PropertyToID("_ReflectColor");//定义一张RT用来存储反射图像的颜色 当颜色缓冲区,在反射平面的Shader中直接用ScreenUV采样
    private static int HashPackedDataRT = Shader.PropertyToID("_HashPackedData"); //定义一张RT来保存对应关系
    //private static int CameraDepthTexture = Shader.PropertyToID("_CameraDepthTexture"); //ComputerShader可以获得相机信息，LoadCameraDepth、LoadCameraColor
    //private static int CameraOpaqueTexture = Shader.PropertyToID("_CameraOpaqueTexture");

    private RenderTargetIdentifier ReflectColorRT_ID = new RenderTargetIdentifier(ReflectColorRT);
    private RenderTargetIdentifier HashPackedDataRT_ID = new RenderTargetIdentifier(HashPackedDataRT);
    //private RenderTargetIdentifier CameraDepthTexture_ID = new RenderTargetIdentifier(CameraDepthTexture);
    //private RenderTargetIdentifier CameraOpaqueTexture_ID = new RenderTargetIdentifier(CameraOpaqueTexture);

    private const int SHADER_NUMTHREAD_X = 8; //must match compute shader's [numthread(x)]
    private const int SHADER_NUMTHREAD_Y = 8; //must match compute shader's [numthread(y)]

    public FilteringSettings FilteringSettings = new FilteringSettings(RenderQueueRange.transparent);

    private int ThreadCountX => Mathf.RoundToInt((float)RTWidth / SHADER_NUMTHREAD_X); //水平方向上的组数
    private int ThreadCountY => Mathf.RoundToInt((float)RTHeight / SHADER_NUMTHREAD_Y); //竖直方向上的组数
    private int ThreadCountZ => 1; //Z方向组数

    [HideInInspector] public string passName = "ScreenSpacePlaneReflectionPass2";

    private RenderTexture ColorRT = null;
    private Texture2DArray ColorBuffer_ = null;
    private Texture2DArray DepthBuffer_ = null;

    protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
    {
        name = "ScreenSpacePlaneReflectionPass";
        RTHeight = RTHeight <= 0 ? 512 : RTHeight;
    }

    protected override void Execute(ScriptableRenderContext renderContext, CommandBuffer cmd, HDCamera hdCamera, CullingResults cullingResult)
    {
        if (enabled && ShouldRenderSSPR)
        {
            if (SsprComputerShader == null)
            {
                Debug.LogError("SSPRcomputeShader丢失！");
                return;
            }

            int ThreadCountX = this.ThreadCountX;
            int ThreadCountY = this.ThreadCountY;
            int ThreadCountZ = this.ThreadCountZ;

            RenderTextureDescriptor rtd = new RenderTextureDescriptor(RTWidth, RTHeight, RenderTextureFormat.Default, 0, 0);//ARGB是用来存颜色通道的 这个图要传给shader 注意我们要a当遮罩 精度我认为单通道8字节足够了
            rtd.sRGB = false;
            rtd.enableRandomWrite = true;//绑定uav

            //PackedDataRT - HashRT
            rtd.colorFormat = RenderTextureFormat.RInt;
            RenderTexture PackedDataRT = RenderTexture.GetTemporary(rtd);
            PackedDataRT.Create();

            //TempTexture
            rtd.colorFormat = RenderTextureFormat.ARGBFloat;
            RenderTexture TempTextureRT = RenderTexture.GetTemporary(rtd);
            TempTextureRT.Create();

            rtd.colorFormat = RenderTextureFormat.ARGBFloat;
            RenderTexture ColorRT = RenderTexture.GetTemporary(rtd);
            TempTextureRT.Create();

            //设置基础参数
            SsprComputerShader.name = "屏幕空间平面反射";
            SsprComputerShader.SetVector(Shader.PropertyToID("_RTSize"), new Vector2(RTWidth, RTHeight));
            SsprComputerShader.SetFloat(Shader.PropertyToID("_ReflectPlaneHeight"), ReflectPlaneHeight);
            SsprComputerShader.SetVector(Shader.PropertyToID("_CameraDirection"), hdCamera.camera.transform.forward);
            SsprComputerShader.SetVector(Shader.PropertyToID("_FinalTintColor"), FinalTintColor);
            SsprComputerShader.SetFloat(Shader.PropertyToID("_FadeOutScreenBorderWidthVerticle"), FadeOutScreenBorderWidthVerticle);
            SsprComputerShader.SetFloat(Shader.PropertyToID("_FadeOutScreenBorderWidthHorizontal"), FadeOutScreenBorderWidthHorizontal);

            Camera camera = hdCamera.camera;
            Matrix4x4 VP = GL.GetGPUProjectionMatrix(camera.projectionMatrix, true) * camera.worldToCameraMatrix;
            //cmd.SetComputeMatrixParam(SsprComputerShader, "_VPMatrix", hdCamera.mainViewConstants.viewProjMatrix);
            //cmd.SetComputeMatrixParam(SsprComputerShader, "_IVPMatrix", hdCamera.mainViewConstants.invViewProjMatrix); //HDRP中获得的是转置结果，所以要转置回去
            SsprComputerShader.SetMatrix(Shader.PropertyToID("_VPMatrix"), VP);
            SsprComputerShader.SetMatrix(Shader.PropertyToID("_IVPMatrix"), VP.inverse);

            //RTHandle colorBuffer, depthBuffer;
            //GetCameraBuffers(out colorBuffer, out depthBuffer);
            //Debug.Log(colorBuffer.rt.mipmapCount);
            //Debug.Log((Texture2DArray)(Texture)colorBuffer);
            ////if (ColorBuffer_ == null) ColorBuffer_ = new Texture2DArray(colorBuffer.rt.width, colorBuffer.rt.height, colorBuffer.rt.depth, DefaultFormat.LDR, TextureCreationFlags.MipChain);
            ////ColorBuffer_.enableRandomWrite = true;

            //RenderTexture colorBuffer_ = new RenderTexture((RenderTexture)colorBuffer);
            //colorBuffer_.volumeDepth = 3;
            //colorBuffer_.dimension = TextureDimension.Tex2DArray;
            //Graphics.CopyTexture(colorBuffer, ColorBuffer_);

            //if (DepthBuffer_ == null) DepthBuffer_ = new Texture2DArray(depthBuffer.rt.width, depthBuffer.rt.height, depthBuffer.rt.depth, DefaultFormat.LDR, TextureCreationFlags.MipChain);

            //DepthBuffer_.enableRandomWrite = true;
            //RenderTexture depthBuffer_ = new RenderTexture((RenderTexture)depthBuffer);
            //Graphics.CopyTexture(depthBuffer, DepthBuffer_);

            //清除历史影响
            int kernel_PathClear = SsprComputerShader.FindKernel("PathClear");
            SsprComputerShader.SetTexture(kernel_PathClear, Shader.PropertyToID("HashRT"), PackedDataRT);
            SsprComputerShader.SetTexture(kernel_PathClear, Shader.PropertyToID("ColorRT"), ColorRT);
            //SsprComputerShader.SetTexture(kernel_PathClear, Shader.PropertyToID("_CameraOpaqueTexture"), colorBuffer); //不用特地传入了
            //SsprComputerShader.SetTexture(kernel_PathClear, Shader.PropertyToID("_CameraDepthTexture"), depthBuffer);
            SsprComputerShader.SetTexture(kernel_PathClear, Shader.PropertyToID("_TempTexture"), TempTextureRT);
            cmd.DispatchCompute(SsprComputerShader, kernel_PathClear, ThreadCountX, ThreadCountY, ThreadCountZ);
            //SsprComputerShader.Dispatch(kernel_PathClear, ThreadCountX, ThreadCountY, ThreadCountZ);

            ////绘制HashRT关系映射
            int kernel_PathRenderHashRT = SsprComputerShader.FindKernel("PathRenderHashRT");
            SsprComputerShader.SetTexture(kernel_PathRenderHashRT, Shader.PropertyToID("HashRT"), PackedDataRT);
            SsprComputerShader.SetTexture(kernel_PathRenderHashRT, Shader.PropertyToID("_TempTexture"), TempTextureRT);
            //SsprComputerShader.SetTexture(kernel_PathRenderHashRT, Shader.PropertyToID("_CameraOpaqueTexture"), colorBuffer);
            //SsprComputerShader.SetTexture(kernel_PathRenderHashRT, Shader.PropertyToID("_CameraDepthTexture"), depthBuffer);
            cmd.DispatchCompute(SsprComputerShader, kernel_PathRenderHashRT, ThreadCountX, ThreadCountY, ThreadCountZ);
            //SsprComputerShader.Dispatch(kernel_PathRenderHashRT, ThreadCountX, ThreadCountY, ThreadCountZ);

            //将反射结果绘制到ColorRT
            int kernel_PathResolveColorRT = SsprComputerShader.FindKernel("PathResolveColorRT");
            //SsprComputerShader.SetTexture(kernel_PathResolveColorRT, Shader.PropertyToID("_CameraOpaqueTexture"), colorBuffer);
            //SsprComputerShader.SetTexture(kernel_PathResolveColorRT, Shader.PropertyToID("_CameraDepthTexture"), depthBuffer);
            SsprComputerShader.SetTexture(kernel_PathResolveColorRT, Shader.PropertyToID("_TempTexture"), TempTextureRT);
            SsprComputerShader.SetTexture(kernel_PathResolveColorRT, Shader.PropertyToID("ColorRT"), ColorRT);
            SsprComputerShader.SetTexture(kernel_PathResolveColorRT, Shader.PropertyToID("HashRT"), PackedDataRT);
            //SsprComputerShader.Dispatch(kernel_PathResolveColorRT, ThreadCountX, ThreadCountY, ThreadCountZ);
            cmd.DispatchCompute(SsprComputerShader, kernel_PathResolveColorRT, ThreadCountX, ThreadCountY, ThreadCountZ);

            //补洞
            int kernel_FillHoles = SsprComputerShader.FindKernel("FillHoles");
            SsprComputerShader.SetTexture(kernel_FillHoles, Shader.PropertyToID("ColorRT"), ColorRT);
            SsprComputerShader.SetTexture(kernel_FillHoles, Shader.PropertyToID("HashRT"), PackedDataRT);
            //SsprComputerShader.Dispatch(kernel_FillHoles, Mathf.CeilToInt(ThreadCountX / 2f), Mathf.CeilToInt(ThreadCountY / 2f), ThreadCountZ);
            cmd.DispatchCompute(SsprComputerShader, kernel_FillHoles, Mathf.CeilToInt(ThreadCountX / 2f), Mathf.CeilToInt(ThreadCountY / 2f), ThreadCountZ);

            if (ReflectionPlaneMesh != null && ReflectionPlaneMaterial != null)
            {
                ReflectionPlaneMaterial.SetTexture(Shader.PropertyToID("_ReflectColor"), ColorRT);
                cmd.DrawMesh(ReflectionPlaneMesh, ReflectionTransform.localToWorldMatrix/*Matrix4x4.TRS(new Vector3(0, 0.16f, 0), Quaternion.identity, Vector3.one)*/, ReflectionPlaneMaterial);
            }
            else
                Debug.Log("未指定Mesh或Material！");

            RenderTexture.ReleaseTemporary(PackedDataRT);
            RenderTexture.ReleaseTemporary(TempTextureRT);
            RenderTexture.ReleaseTemporary(ColorRT);
        }
        //renderContext.ExecuteCommandBuffer(cmd);
        //cmd.Clear();
        //renderContext.Submit();

        //DrawingSettings drawingSettings = new DrawingSettings(lightMode_SSPR_sti, new SortingSettings(hdCamera.camera));//CreateDrawingSettings(lightMode_SSPR_sti, ref renderingData, SortingCriteria.CommonOpaque);
        ////drawingSettings.SetShaderPassName(0, lightMode_SSPR_sti);
        //FilteringSettings filteringSettings = FilteringSettings.defaultValue;
        ////NativeArray<ShaderTagId> re = new NativeArray<ShaderTagId>(new ShaderTagId[] { lightMode_SSPR_sti }, Allocator.Temp);
        //renderContext.DrawRenderers(cullingResult, ref drawingSettings, ref filteringSettings);

        //renderContext.Submit();
    }

    protected override void Cleanup()
    {
    }
}